/*
 brief: 委托函数，安全回调目标函数。 功能类似函数指针，但代码编写不容易犯错。
		应用场景比较少。一般用接口 或者 WeakPtr 代码会更简单。
		参考虚幻引擎的委托，简化版。
应用场景：
	需要代理函数，能保存多种类型可调用对象： 函数指针，函数对象，类成员函数指针，lambda

 例子
	class ConcreteClass : public su::EnableWeakPtr<ConcreteClass>
	{
	public:
		void Fun(int i){}
	};

	//regist
	DelegateFun<void, int> delegateFun;
	{
		ConcreteClass a;
		delegateFun.Set(a, &ConcreteClass::fun1);
	}

	//safely fire
	delegateFun.Excute(4);


*/

#pragma once
#include "typedef.h"
#include "misc.h"
#include <functional>



template<typename RetType, typename... Args>
class DelegateFun
{
	std::function<RetType(Args...)> m_funObj;

	template<class Obj>
	class ObjTrait
	{
	public:
		constexpr static bool IsWeakPtrClass(const su::EnableWeakPtr<Obj>*) { return true; }
		constexpr static bool IsWeakPtrClass(...) { return false; }
	};
public:

	template<class Obj>
	void Set(Obj& obj, RetType(Obj::* fun)(Args...))
	{
		static_assert(ObjTrait<Obj>::IsWeakPtrClass((const Obj*)nullptr), "You must use EnableWeakPtr<Obj> obj");
		su::WeakPtr<Obj> weakObj = obj;
		auto f = [weakObj, fun](Args&& ... args)->RetType
		{
			su::WeakPtr<Obj> noconst = weakObj;//再赋值，取消 const修饰
			if (Obj* p = noconst.Get())
			{
				return (p->*fun)(std::forward<Args>(args)...);
			}
			return RetType();
		};
		m_funObj = f;
	}

	void Set(std::function<RetType(Args...)> funObj)
	{
		m_funObj = funObj;
	}

	RetType Excute(Args&& ... args)
	{
		if (m_funObj)
		{
			return m_funObj(std::forward<Args>(args)...);
		}
		return RetType();
	}

	void Clear()
	{
		m_funObj = nullptr;
	}
};

